package sw6.launcher;

import girafPlace.lib.Application;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.List;

import sw6.launcher.TableInfo.Applications;
import sw6.lib.Settings;
import sw6.lib.user.Profile;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class IconAdapter extends BaseAdapter {
	private static Context mContext;
	protected final String tag = "GIRAF";
	protected List<String> applications; //Package names
	protected List<Drawable> icons;
	protected List<String> labels;
	protected int size = 0;
	
	private static IconAdapter instance = null;
	private IconAdapter() {
		// Exists only to defeat instantiation.
	}
	public static IconAdapter getInstance(Context context) {
		mContext = context;
		if(instance == null) {
			instance = new IconAdapter();
			instance.FindApps();
		}
		return instance;
	}
    
    /** Gets the number of installed GIRAF applications */
	@Override
	public int getCount() {
			return size;
	}
	
	/** Gets the ResolveInfo object at the given position. */
	@Override
	public Object getItem(int position) {
		if(applications == null)
			return null;
		else
			return applications.get(position);
	}

	/** Not Used */
	@Override
	public long getItemId(int position) {
		return position;
	}

	/** Gets the ImageView for the given position. */
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Log.d(tag, "Requesting id " + position + " When the number of applications is: " + applications.size());
		Icon icon;
        if (convertView == null) {  // if it's not recycled, initialize some attributes
            icon = new Icon(mContext);
            
        } else {
            icon = (Icon) convertView;
        }
        Log.d(tag,String.format("Getting the icon for position %1$d", position));
        icon.setImageDrawable(icons.get(position));
        icon.setText(labels.get(position));
        return icon;
	}

	private void FindApps() {
		new AsyncLoader().execute();
	}
	
	public void updateApps() {
		new AsyncLoader().execute();
	}
	
	/**
	 * Class for loading the applications and there icons. 
	 * It will provide the user with a loading screen.
	 * @author rune
	 *
	 */
	private class AsyncLoader extends AsyncTask<Void,Void,Void> {
		ProgressDialog loadingDialog;
		
		@Override
		protected void onPreExecute() {
			loadingDialog = ProgressDialog.show(mContext, "Loading", "Please wait while the applications are being loaded",true,false);
			size = 0;
			notifyDataSetInvalidated();
			super.onPreExecute();
		}
		
		@Override
		protected Void doInBackground(Void... params) {
			applications = buildInfos();
			icons = buildIcons();
			labels = buildLabels();
			
			size = applications.size();
			
			
			return null;
		}
		
		@Override
		protected void onPostExecute(Void result) {
			try {
				loadingDialog.dismiss();
			} catch (Exception e) {
				Log.e("GIRAF", "Could not dismiss dialog");
			}
			
			notifyDataSetChanged();
			super.onPostExecute(result);
		}
	}
	
	/**
	 * Gets the list of applications with the "sw6.intent.action.MAIN" 
	 * intent from the packagemanager. It is only used internally by this adapter.
	 * NOTE: THIS VERSION USES "android.intent.action.MAIN"!!
	 * @return A list of ResolveInfos containing the applications to be launched.
	 */
	@SuppressWarnings("unchecked")
	private List<String> buildInfos() {
		List<String> SSIDS = getSSIDS();
		List<String> result = new ArrayList<String>();
		
		String[] projection = {Applications._ID, Applications.PACKAGE_NAME,Applications.SSID_BLACKLIST,Applications.APPLICATION_OBJECT};
		
		
		Cursor cursor = mContext.getContentResolver().query(Uri.parse("content://" + TableInfo.AUTHORITY + "/applications"), projection, null, null, null);
		
		Application app = null;
		List<String> SSIDBlackList = getSSIDS();
		
		if(cursor.moveToFirst()) {
			do {
				
				    ByteArrayInputStream bis = new ByteArrayInputStream (cursor.getBlob(cursor.getColumnIndex(Applications.APPLICATION_OBJECT)));
				    ObjectInputStream ois;
					try {
						ois = new ObjectInputStream (bis);
						app = (Application) ois.readObject();
					} catch (StreamCorruptedException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					} catch (ClassNotFoundException e) {
						Log.e(tag,"The application class could not be found");
					}
				    
				
				    Log.d(tag,"Checking application: " + app.getPackage());
				    
				    Profile profile = Settings.getUserProfile(mContext);
				    
				    if (!profile.canDragAndDrop() && app.isCanDragAndDrop()) {
						break;
					}
					
					if (!profile.canHear() && app.isCanHear()) {
						break;
					}
					
					if (!profile.requreSimpleVisualEffects() && app.isRequiresSimpleVisualEffects()) {
						break;
					}
					
					if (!profile.canAnalogTime() && app.isCanAnalogTime()) {
						break;
					}
					
					if (!profile.canDigitalTime() && app.isCanDigitalTime()) {
						break;
					}
					
					if (!profile.canRead() && app.isCanRead()) {
						break;
					}
					
					if (!profile.hasBadVision() && app.isHasBadVision()) {
						break;
					}
					
					if (!profile.requresLargeButtons() && app.isRequiresLargeButtons()) {
						break;
					}
					
					if (!profile.canSpeak() && app.isCanSpeak()) {
						break;
					}
					
					if (!profile.canNumbers() && app.isCanNumbers()) {
						break;
					}
					
					if (!profile.canUseKeyboard() && app.isCanUseKeyboard()) {
						break;
					}
					
					Log.d(tag,"Passed userprofile");
				    
					try{
						ByteArrayInputStream bis2 = new ByteArrayInputStream (cursor.getBlob(cursor.getColumnIndex(Applications.SSID_BLACKLIST)));
						ObjectInputStream ois2 = new ObjectInputStream (bis2);
						SSIDBlackList = (ArrayList<String>) ois2.readObject();
					} catch (ClassNotFoundException e) {
						Log.e(tag,"The arraylist class could not be found");
					} catch (StreamCorruptedException e) {
						Log.e(tag,"The stream for the blacklist was corupted!");
					} catch (IOException e) {
						Log.e(tag,"The was an IOException: " + e.getMessage());
					} 
				    
				    if(compareSSIDS(SSIDBlackList,SSIDS)) break;
				    
				    Log.d(tag,"Passed compare");
				    
				    result.add(cursor.getString(cursor.getColumnIndex(Applications.PACKAGE_NAME)));
				    
				
			}while(cursor.moveToNext());
			cursor.close();
		}
		
		return result;
	}
	
	
	/**
	 * Compares two list of string. Will return true if a string is on both lists
	 * @param sSIDBlackList The first list
	 * @param sSIDS The second list
	 * @return True if a string is on both lists, otherwise false
	 */
	private boolean compareSSIDS(List<String> sSIDBlackList, List<String> sSIDS) {
		for(String ssidBlack : sSIDBlackList) {
			for(String ssid : sSIDS )
				if(ssid.compareTo(ssidBlack) == 0) return true;
		}
		return false;
	}
	private List<String> getSSIDS() {
		List<String> result = new ArrayList<String>();
		
		WifiManager wm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
		wm.setWifiEnabled(true);
		wm.startScan();
		
		for(ScanResult sr : wm.getScanResults()) {
			result.add(sr.SSID);
		}
		
		return result;
	}
	private List<String> buildLabels() {
		List<String> result = new ArrayList<String>();
		
		for(String info: applications) {
			try {
				result.add((String) mContext.getPackageManager().getPackageInfo(info, 0).applicationInfo.loadLabel(mContext.getPackageManager()));
			} catch (NameNotFoundException e) {
				Log.e(tag,e.getMessage());
			}
		}
		return result;
	}
	
	/** Loads all icons from the ResolveInfo's in the applications list. */
	private List<Drawable> buildIcons() {
		List<Drawable> result = new ArrayList<Drawable>();
		
		for(String info: applications) {
			try {
				result.add(mContext.getPackageManager().getPackageInfo(info, 0).applicationInfo.loadIcon(mContext.getPackageManager()));
			} catch (NameNotFoundException e) {
				Log.e(tag,e.getMessage());
			}
		}
		
		return result;
	}
}
	